關於單元測試的部分,我找到我的API部分有一個小功能蠻適合拿來做練習:
function validSkillsForRace($skills, $race) {
$allowedSkills = $race->skills->pluck('id')->toArray();
foreach ($skills as $skillId) {
if (!in_array($skillId, $allowedSkills)) {
return false;
}
}
return true;
}
這是我在使用者輸入參數新增寶可夢時,我進行表單驗證的時候,會用到的一個自定義邏輯,簡單講解一下:
目的
我會用這個驗證是因為我的技能欄位是用陣列來儲存,使用者可以輸入1~4個技能,所以我要一個一個去比對這些技能是否為該寶可夢可以學習的技能。
功能細節
在前面的部分有提到模擬(mocking)的部分的用意,而我們這裡需要模擬的對象就是會實際對資料庫做查找的部分,以我上述的例子就是這段:
$race->skills->pluck('id')
$race->skills
:
BelongsToMany
關聯的實例,代表 race
和 skills
之間的多對多關係。BelongsToMany
關聯中取得資料時(例如像 $race->skills->pluck('id')
這樣的操作),它會隱式地調用 getResults()
方法以從資料庫取得相對應的 skills
。getResults()
:
Collection
實例,其中包含與該 race
相關的所有 skills
。$race->skills->pluck('id')
:
Collection
實例上調用 pluck
方法,從集合中取得每個 skill
的 id
值,並返回這些值的集合。這裡我必須將這段會返回的物件都做創建模擬物件(以上述來說的話就是$race、BelongsToMany、Collection這些實例):
public function testValidSkillsForRaceIftheSkillsExist()
{
// 创建 Race 类的模拟对象
$raceMock = $this->getMockBuilder(Race::class)
->onlyMethods(['skills']) // 指定仅模拟 `skills` 方法
->getMock();
// 创建 Collection 类的模拟对象
// 模拟了 BelongsToMany 关系类的一个实例,用来模拟 $race->skills 的返回值。
$skillsRelationMock = $this->createMock(BelongsToMany::class);
// 模拟了 Collection 类的一个实例,用来模拟 $race->skills->pluck('id') 的返回值。
$skillsCollectionMock = $this->createMock(Collection::class);
這裡簡單來說就是我創建了:
Race、BelongsToMany、collecetion類的模擬物件。
// 修改这里:使 `pluck` 返回 Collection 对象而不是数组
$skillsCollectionMock->method('pluck')
->willReturn(collect([1, 2, 3]));
// Laravel 在底层会调用 getResults 来获取这个关系对应的模型集合。
$skillsRelationMock->method('getResults')
->willReturn($skillsCollectionMock);
$raceMock->method('skills')
->willReturn($skillsRelationMock);
// 上述過程都在模擬$race->skills->pluck('id')
這裡我讓整個我是將$race->skills->pluck('id')整個過程都用模擬物件先定義好,
也就是當我在call這些物件的某些方法的時候他會如何去執行,
比如 $raceMock->method('skills')
->willReturn($skillsRelationMock);
這裡就是當我$race去→skills的時候,原本返回的事BelongsToMany物件,這裡返回的是我創建的模擬物件。
// 调用待测函数,并检查返回值
$result = validSkillsForRace([1, 2], $raceMock);
// 断言结果为真
$this->assertTrue($result);
}
最後我就可以實際去呼叫我要測試的函式,除了傳入原本需要傳入的技能id陣列,還有剛剛模擬的物件,這樣在我實際函數裡面$race物件去資料庫撈資料的時候,他會去用模擬的方式得到[1,2,3]陣列。
這裡我其實並沒有把我整個專案裡面的測試都寫完,我主要還是以練習為導向,所以挑了一些測試對象來練習FeatureTest及UnitTest,實際上一定更複雜要注意的事情更多,這裡就是單純跟大家分享我初次練習測試的小心得,希望未來需要寫的時候能有一個初步了解。